<?php

class Exam_Api_Category extends Core_Api_Abstract
{	
		
	/**
	 * Get all categories and reorder
	 * @return: array
	 */
	public function getExamCategoryTree() {
		$categories = $this->getAllExamCategories();		
		return $this->getExamCategoryChildrens($categories);
	}
	
	/**
	 * Get all categories
	 * @return: Zend_Db_Table_Rowset $categories
	 */
	public function getAllExamCategories() {
		$table = Engine_Api::_()->getDbTable('categories', 'exam');
		$select = $table->select()
			->order('parent_id ASC')
			->order('category_id ASC');
		return $table->fetchAll($select);
	}
	
	/**
	 * Reorder
	 * @param Zend_Db_Table_Rowset $categories
	 * @param int $parentId
	 * @param Zend_Db_Table_Row[] $parentCategories
	 * @return array
	 */
	public function getExamCategoryChildrens($categories, $parentId = 0, $parentCategories = array()) {
		$tree = array();		
		
		// check
		if (!is_numeric($parentId)) {
			return $tree;
		}
		
		// int
		$parentId = intval($parentId);
		
		// rewind
		$i = 0;
		
		// count row
		$countRow = $categories->count();

		while ($i < $countRow) {
			
			// get row			
			$row = $categories->getRow($i);
			// increase position
			$i++;
//			print_r($row->parent_id);
//            echo '-';
//            print_r($parentId);
//            echo '<br>';
			// is a child
			if ($row->parent_id == $parentId) {
				$child = array();			
					
				// set id
				$child['id'] = $row->category_id;				
				
                	
				// set info
				$child['info'] = $row;
				
				// set array of parent categories
				if (!empty($parentCategories)) {
					$child['parents'] = $parentCategories;
				}

				// recursive
				$children = $this->getExamCategoryChildrens($categories, $row->category_id, array_merge($parentCategories, array($child)));			
				
				
				// have children
				if (!empty($children)) {
					$child['children'] = $children;
				}
				
				$tree[] = $child;
			}
		}
		return $tree;
	}
	
	/**
	 * Get all children category ID in tree
	 * @param array $tree: return of getExamCategoryTree() or a branch of tree
	 * @return int[] $ids
	 */
	public function getExamTreeChildrenCategoryId($tree) {
		$ids = array();
		
		// check
		if (!is_array($tree)) {
			return $ids;
		}
		
		foreach ($tree as $category) {
			// get id
			$ids[] = $category['id'];
			
			// have children
			if (isset($category['children'])) {
				
				// recursive
				$childIds = $this->getExamTreeChildrenCategoryId($category['children']);
				
				// merge
				$ids = array_merge($ids, $childIds);
			}
		}

		return $ids;
	}
	
	/**
	 * Get all categories id of a category item (include its self id)
	 * @param array $category: category item
	 * @return int[] $ids
	 */
	public function getExamTreeCategoriesId($category) {
		// it's id
		$ids = array($category['id']);
		
		// children id
		if (!empty($category['children'])) {
			$childrenId = $this->getExamTreeChildrenCategoryId($category['children']);
			$ids = array_merge($ids, $childrenId);
		}
		return $ids;
	}
	
	/**
	 * Get category by Id	 
	 * @param int $cateId
	 * @param array $tree: return of getExamCategoryTree() or a branch of tree
	 * @return array $category
	 */
	public function getExamTreeCategoryById($cateId, $tree) {
		$category = null;
		// check
		if (!is_array($tree) || !is_numeric($cateId)) {
			return $category;
		}
		
		foreach ($tree as $item) {
			if ($item['id'] == $cateId) {
				return $item;
			}
			// check children
			if (isset($item['children'])) {
				$recursiveReturn = $this->getExamTreeCategoryById($cateId, $item['children']);
				if (!empty($recursiveReturn)) {
					return $recursiveReturn;
				}
			}
		}
		return $category;
	}
	
	/**
	 * Get tree XML Text
	 * @param array $tree: return of getExamCategoryTree() or a branch of tree
	 * @param boolean $isShowRoot: whether show root element or not
	 * @param int $selectedId: selected category id
	 * @param int $excludedId: excluded category id
	 * @return string $xmlTxt
	 */
	public function getExamTreeXML($tree, $isShowRoot = false, $selectedId = null, $excludedId = null, $rootName = "Root") {
		$xmlDoc = $this->getExamTreeXMLDOM($tree, $isShowRoot, $selectedId, $excludedId, $rootName);
		return $xmlDoc->saveXML();
	}
	
	/**
	 * Get tree XML DOM
	 * @param array $tree: return of getExamCategoryTree() or a branch of tree
	 * @param boolean $isShowRoot: whether show root element or not
	 * @param int $selectedId: selected category id
	 * @param int $excludedId: excluded category id
	 * @return DOMDocument $xmlDoc
	 */
	public function getExamTreeXMLDOM($tree, $isShowRoot = false, $selectedId = null, $excludedId = null, $rootName = "Root") {		
		// check
		if (!is_array($tree)
			|| (!is_numeric($selectedId) && !is_null($selectedId)) 
			|| (!is_numeric($excludedId) && !is_null($excludedId)) 
		) {
			return null;
		}
		
		// create dom document
		$xmlDoc = new DOMDocument('1.0', 'UTF-8');
		
		// root element
		$rootEl = $xmlDoc->createElement('TREE');
		
		// get items
		$items = $this->getExamTreeXMLDOMElements($xmlDoc, $tree, $selectedId, $excludedId);		
		
		// root item
		if ($isShowRoot) {
			// get translate
			$translate = Zend_Registry::get('Zend_Translate');
			
			// create root item
			$rootItemEl = $xmlDoc->createElement('ITEM');
			// set attribute
			$rootItemEl->setAttribute("state", "expanding");
			
			// create title, value element
			$rootItemTitleEl = $xmlDoc->createElement('TEXT', $translate->translate($rootName));
			$rootItemValueEl = $xmlDoc->createElement('VALUE', 0);
			
			// append to root item
			$rootItemEl->appendChild($rootItemTitleEl);
			$rootItemEl->appendChild($rootItemValueEl);		
			
			if (!empty($items)) {
				// create sub item
				$rootSubItemEl = $xmlDoc->createElement('SUB');
				
				// append items to sub item
				foreach ($items as $item) {
					$rootSubItemEl->appendChild($item);
				}
				
				// append sub item to root item
				$rootItemEl->appendChild($rootSubItemEl);
			}
			// append root item to root element
			$rootEl->appendChild($rootItemEl);
		}
		else if(is_array($items)){
			foreach ($items as $item) {
				$rootEl->appendChild($item);
			}
		}
		
		$xmlDoc->appendChild($rootEl);
		return $xmlDoc;
	}
	
	/**
	 * Get tree XML DOM Elements
	 * @param DOMDocument $xmlDoc
	 * @param array $tree: return of getExamCategoryTree() or a branch of tree
	 * @param int $selectedId: selected category id
	 * @param int $excludedId: excluded category id
	 * @return DOMElement[] $elements
	 */
	public function getExamTreeXMLDOMElements($xmlDoc, $tree, $selectedId = null, $excludedId = null) {
		$element = null;
		
		// check
		if (!is_array($tree) || empty($tree) 
			|| (!is_numeric($selectedId) && !is_null($selectedId)) 
			|| (!is_numeric($excludedId) && !is_null($excludedId)) 
		) {
			return $element;
		}
		
		$elements = array();
		
		foreach ($tree as $item) {
			// excluded item
			if ($item['id'] == $excludedId && !is_null($excludedId)) {
				continue;
			}
			
			$element = $xmlDoc->createElement('ITEM');
			
			// selected item
			if ($item['id'] == $selectedId && !is_null($selectedId)) {
				$element->setAttribute('selected', 'true');
			}
			
			// title
			$title = $xmlDoc->createElement('TEXT');
			$textNode = $xmlDoc->createTextNode($item['info']->category_name);
			$title->appendChild($textNode);
			$element->appendChild($title);

			// id
			$id = $xmlDoc->createElement('VALUE', $item['info']->category_id);
			$element->appendChild($id);
			
			// recursive
			if (isset($item['children'])) {
				$children = $this->getExamTreeXMLDOMElements($xmlDoc, $item['children'], $selectedId, $excludedId);
				if (!empty($children) && is_array($children)) {
					// create sub element
					$subElement = $xmlDoc->createElement('SUB');
					
					// append children to sub elements
					foreach ($children as $child) {
						$subElement->appendChild($child);
					}
					
					// add to element
					$element->appendChild($subElement);
				}
			}

			// add to array
			$elements[] = $element;
			
		}
		
		return $elements;
	}
	
	/**
	 * Delete category and all children of it
	 * @param array $category: return of getExamTreeCategoryById() function
	 */
	/*
	public function deleteCategory($category) {
		// delete it
		$category['info']->delete();
		
		// delete children
		if (isset($category['children'])) {
			foreach ($category['children'] as $child) {
				$this->deleteCategory($child);
			}
		}
	}
	*/
    
    public function tree2StageCategories($first = true) {
        // 2 stage only
        $tb = Engine_Api::_()->getDbTable('Categories', 'Exam');
        $sl = $tb->select()->where('parent_id = 0')->order('category_id ASC');
        $rs = $tb->fetchAll($sl);
        if ($first == true) $categories = array('' => '');
        else $categories = array();
        foreach ($rs as $item) {
            $categories[$item->category_id] = $item->category_name; 
            $sl = $tb->select()->where('parent_id = ?', $item->getIdentity())->order('category_id ASC'); 
            $cd = $tb->fetchAll($sl);  
            foreach ($cd as $child) {
                $categories[$child->getIdentity()] = "-- " . $child->category_name;
            }            
        } 
        return $categories;
    }
}
